import { defineComponent, reactive, toRefs, computed, watch, onMounted, getCurrentInstance } from "vue"
import { inject } from "vue"
import { provide } from "vue"

import BodyTr from "./body-tr"
import BodyTrScrolling from "./body-tr-scrolling"
import ExpandTr from "./expand-tr"
import VueDomResizeObserver from "amtf/components/resize-observer"
import { getDomResizeObserverCompKey, getFixedTotalWidthByColumnKey } from "../util"

import emitter from "amtf/utils/emitter"
import { useEmitter } from "amtf/hooks"

import { use样式 } from "amtf/hooks"
import { getValByUnit, 拼组件名, isFunction, isBoolean, getRandomId } from "amtf/utils"
const 主名 = "table-body"
const 组件名 = 拼组件名(主名)

import { EMIT_EVENTS, COLUMN_TYPES, EXPAND_TRIGGER_TYPES } from "../util/constant"

export default defineComponent({
    name: 组件名,
    props: {
        tableViewportWidth: {
            type: Number,
            default: 0,
        },
        columnsOptionResetTime: {
            type: Number,
            default: 0,
        },
        colgroups: {
            type: Array,
            required: true,
        },
        actualRenderTableData: {
            type: Array,
            required: true,
        },
        hasFixedColumn: {
            type: Boolean,
            default: false,
        },
        allRowKeys: {
            type: Array,
            required: true,
        },
        // expand row option
        expandOption: {
            type: Object,
            default: () => null,
        },
        // checkbox option
        checkboxOption: {
            type: Object,
            default: () => null,
        },
        // radio option
        radioOption: {
            type: Object,
            default: () => null,
        },
        // virual scroll
        virtualScrollOption: {
            type: Object,
            default: null,
        },
        // is virtual scroll
        isVirtualScroll: {
            type: Boolean,
            default: false,
        },
        // is scrolling
        showVirtualScrollingPlaceholder: {
            type: Boolean,
            default: false,
        },
        rowKeyFieldName: {
            type: String,
            default: null,
        },
        // cell style option
        cellStyleOption: {
            type: Object,
            default: () => null,
        },
        // cell span option
        cellSpanOption: {
            type: Object,
            default: () => null,
        },
        // highlight row key
        highlightRowKey: {
            type: [String, Number],
            default: null,
        },
        // event custom option
        eventCustomOption: {
            type: Object,
            default: () => null,
        },
        // cell selection option
        cellSelectionOption: {
            type: Object,
            default: () => null,
        },
        // cell selection data
        cellSelectionData: {
            type: Object,
            default: () => null,
        },
        // cell selection range data
        cellSelectionRangeData: {
            type: Object,
            default: () => null,
        },
        bodyIndicatorRowKeys: {
            type: Object,
            default: () => null,
        },
        // edit option
        editOption: {
            type: Object,
            default: () => null,
        },
    },
    setup(props, { emit }) {
        const instance = getCurrentInstance()
        const bodyid = instance.uid
        provide("bodyid", bodyid)
        // console.log(`body props 👉`, props)
        const { dispatch } = useEmitter(inject("表格id"))

        const { 拼样式名_table直属 } = use样式(主名)

        const state = reactive({
            colsWidths: new Map(),
            internalExpandRowkeys: [],
            internalCheckboxSelectedRowKeys: [],
            internalRadioSelectedRowKey: null,
            virtualScrollPreviewRenderedRowKeys: [],
            virtualScrollRepeatRenderedRowKeys: [],
        })

        const columnCollection = computed(() => {
            let _columnCollection = []
            const { colgroups } = props
            colgroups.forEach(col => {
                const colKey = col.key
                let columnCollectionItem = {
                    colKey: colKey,
                    class: {
                        [拼样式名_table直属("last-left-fixed-column")]: isLastLeftFixedColumn(col),
                        [拼样式名_table直属("first-right-fixed-column")]: isfirstRightFixedColumn(col),
                    },
                    style: {},
                }
                const { fixed, align } = col
                columnCollectionItem.style["text-align"] = align || "center"
                if (fixed) {
                    let totalWidth = 0
                    const columnIndex = colgroups.findIndex(x => x.key === colKey)
                    if (
                        (fixed === "left" && columnIndex > 0) ||
                        (fixed === "right" && columnIndex < colgroups.length - 1)
                    ) {
                        totalWidth = getFixedTotalWidthByColumnKey({
                            colgroups,
                            colKey,
                            fixed,
                        })
                        // console.log(`totalWidth 👉`, totalWidth)
                        totalWidth = getValByUnit(totalWidth)
                    }
                    columnCollectionItem.style["left"] = fixed === "left" ? totalWidth : ""
                    columnCollectionItem.style["right"] = fixed === "right" ? totalWidth : ""
                    // console.log(`columnCollectionItem 👉`, columnCollectionItem)
                }
                _columnCollection.push(columnCollectionItem)
            })
            // console.log(`_columnCollection 👉`, _columnCollection)
            return _columnCollection
        })

        const expandColumn = computed(() => props.colgroups.find(x => x.type === COLUMN_TYPES.EXPAND))

        const isControlledExpand = computed(() => {
            return props.expandOption && Array.isArray(props.expandOption.expandedRowKeys)
        })

        const expandedRowkeys = computed(() => {
            return isControlledExpand.value ? props.expandOption.expandedRowKeys : state.internalExpandRowkeys
        })

        const disableCheckboxSelectedRowKeys = computed(() => {
            let result = []
            const { checkboxOption, internalCheckboxSelectedRowKeys } = props
            if (!checkboxOption) {
                return result
            }
            const { disableSelectedRowKeys } = checkboxOption
            if (
                internalCheckboxSelectedRowKeys.length > 0 &&
                Array.isArray(disableSelectedRowKeys) &&
                disableSelectedRowKeys.length > 0
            ) {
                disableSelectedRowKeys.forEach(rowkey => {
                    if (internalCheckboxSelectedRowKeys.includes(rowkey)) {
                        result.push(rowkey)
                    }
                })
            }
            return result
        })

        const disableCheckboxUnselectedRowKeys = computed(() => {
            let result = []
            const { checkboxOption } = props
            if (!checkboxOption) {
                return result
            }
            const { disableSelectedRowKeys } = checkboxOption
            if (Array.isArray(disableSelectedRowKeys) && disableSelectedRowKeys.length > 0) {
                disableSelectedRowKeys.forEach(rowkey => {
                    if (!props.internalCheckboxSelectedRowKeys.includes(rowkey)) {
                        result.push(rowkey)
                    }
                })
            }
            return result
        })

        const isCheckboxSelectedAll = computed(() => {
            if (props.allRowKeys.length > 0) {
                if (
                    props.internalCheckboxSelectedRowKeys.length + disableCheckboxUnselectedRowKeys.value.length ===
                    props.allRowKeys.length
                ) {
                    return true
                }
            }
            return false
        })

        const isCheckboxIndeterminate = computed(() => {
            const { internalCheckboxSelectedRowKeys, allRowKeys } = props
            return (
                internalCheckboxSelectedRowKeys.length > 0 && internalCheckboxSelectedRowKeys.length < allRowKeys.length
            )
        })

        const isControlledRadio = computed(() => {
            const { radioOption } = props
            return radioOption && Object.keys(radioOption).includes("selectedRowKey")
        })

        function isLastLeftFixedColumn(column) {
            let result = false
            const { colgroups } = props
            const { fixed } = column
            if (fixed === "left") {
                const { field } = column
                const leftFixedColumns = colgroups.filter(x => x.fixed === "left")
                const index = leftFixedColumns.findIndex(x => x.field === field)
                if (index === leftFixedColumns.length - 1) {
                    result = true
                }
            }
            return result
        }

        function isfirstRightFixedColumn(column) {
            let result = false
            const { colgroups } = props
            const { fixed } = column
            if (fixed === "right") {
                const { field } = column
                const rightFixedColumns = colgroups.filter(x => x.fixed === "right")
                if (rightFixedColumns[0].field === field) {
                    result = true
                }
            }
            return result
        }

        function expandRowChange(rowData, rowIndex) {
            const { expandOption, internalExpandRowkeys, rowKeyFieldName } = props
            if (typeof expandOption.beforeExpandRowChange === "function") {
                const beforeExpandRowResult = expandOption.beforeExpandRowChange({
                    beforeExpandedRowKeys: expandedRowkeys.value,
                    row: rowData,
                    rowIndex,
                })
                if (beforeExpandRowResult === false) {
                    return false
                }
            }
            const rowKey = rowData[rowKeyFieldName]
            const rowKeyIndex = internalExpandRowkeys.indexOf(rowKey)
            if (rowKeyIndex > -1) {
                internalExpandRowkeys.splice(rowKeyIndex, 1)
            } else {
                internalExpandRowkeys.push(rowKey)
            }
            if (typeof expandOption.afterExpandRowChange === "function") {
                expandOption.afterExpandRowChange({
                    afterExpandedRowKeys: internalExpandRowkeys,
                    row: rowData,
                    rowIndex,
                })
            }
        }

        function 点击行({ rowData, rowIndex }) {
            // console.log(`body 点击行  ing👇`)
            const { expandOption, expandRowChange, rowKeyFieldName } = props
            if (rowKeyFieldName) {
                const rowKey = rowData[rowKeyFieldName]
                // dispatch(EMIT_EVENTS.HIGHLIGHT_ROW_CHANGE, { rowKey })
                emit(EMIT_EVENTS.HIGHLIGHT_ROW_CHANGE, { rowKey })
            }
            if (!isExpandRow({ rowData, rowIndex })) {
                return false
            }
            const trigger = expandOption.trigger
            if (trigger === EXPAND_TRIGGER_TYPES.ROW) {
                expandRowChange(rowData, rowIndex)
            }
        }

        function isExpandRow({ rowData, rowIndex }) {
            let result = false
            const { expandColumn, expandOption } = props
            if (expandColumn && expandOption) {
                let expandable = true
                if (typeof expandOption.expandable === "function") {
                    expandable = expandOption.expandable({
                        row: rowData,
                        column: expandColumn.value,
                        rowIndex,
                    })
                }
                if (expandable !== false) {
                    result = true
                }
            }
            return result
        }

        function tdSizeChange({ key, width }) {
            state.colsWidths.set(key, width)
            // console.log(`触发宽度改变事件 ing👇`)
            // dispatch(EMIT_EVENTS.BODY_CELL_WIDTH_CHANGE, state.colsWidths)
            emit(EMIT_EVENTS.BODY_CELL_WIDTH_CHANGE, state.colsWidths)
        }

        function initInternalExpandRowKeys() {
            const { expandOption, isControlledExpand, allRowKeys } = props
            if (!expandOption) {
                return false
            }
            if (isControlledExpand.value) {
                state.internalExpandRowkeys = expandOption.expandedRowKeys.slice(0)
            } else if (expandOption.defaultExpandAllRows) {
                state.internalExpandRowkeys = allRowKeys
            } else if (expandOption.defaultExpandedRowKeys) {
                state.internalExpandRowkeys = expandOption.defaultExpandedRowKeys.slice(0)
            }
        }

        function getExpandRowComp({ rowData, rowIndex }) {
            if (isExpandRow({ rowData, rowIndex })) {
                const expandTrProps = {
                    tableViewportWidth: props.tableViewportWidth,
                    colgroups: props.colgroups,
                    expandOption: props.expandOption,
                    expandedRowkeys: expandedRowkeys.value,
                    expandColumn: expandColumn.value,
                    rowKeyFieldName: props.rowKeyFieldName,
                    rowData,
                    rowIndex,
                }
                return <ExpandTr {...expandTrProps} />
            }
            return null
        }

        function sendToCheckboxAll() {
            const { isCheckboxSelectedAll, isCheckboxIndeterminate } = props
            dispatch(EMIT_EVENTS.CHECKBOX_SELECTED_ALL_INFO, {
                isIndeterminate: isCheckboxIndeterminate.value,
                isSelected: isCheckboxSelectedAll.value,
            })
        }

        function initInternalRadioSelectedRowKey() {
            const { radioOption, isControlledRadio } = props
            if (!radioOption) {
                return false
            }
            const { selectedRowKey, defaultSelectedRowKey } = radioOption
            state.internalRadioSelectedRowKey = isControlledRadio ? selectedRowKey : defaultSelectedRowKey
        }

        function initInternalCheckboxSelectedRowKeys() {
            let result = []
            const { checkboxOption, allRowKeys } = props
            if (!checkboxOption) {
                return false
            }
            const { selectedRowKeys, defaultSelectedAllRows, defaultSelectedRowKeys } = checkboxOption
            if (Array.isArray(selectedRowKeys)) {
                result = selectedRowKeys
            } else if (defaultSelectedAllRows) {
                result = allRowKeys
            } else if (Array.isArray(defaultSelectedRowKeys)) {
                result = defaultSelectedRowKeys
            }
            state.internalCheckboxSelectedRowKeys = result
        }

        function resetInternalCheckboxSelectedRowKeys() {
            state.internalCheckboxSelectedRowKeys = props.checkboxOption.selectedRowKeys.slice(0)
        }

        function checkboxSelectedRowChange({ rowKey, isSelected }) {
            const { checkboxOption, internalCheckboxSelectedRowKeys, rowKeyFieldName } = props
            const { selectedRowChange, selectedRowKeys } = checkboxOption
            let internalCheckboxSelectedRowKeysTemp = internalCheckboxSelectedRowKeys.slice(0)
            if (isSelected) {
                const rowKeyIndex = internalCheckboxSelectedRowKeysTemp.indexOf(rowKey)
                if (rowKeyIndex === -1) {
                    internalCheckboxSelectedRowKeysTemp.push(rowKey)
                }
            } else {
                const rowKeyIndex = internalCheckboxSelectedRowKeysTemp.indexOf(rowKey)
                if (rowKeyIndex > -1) {
                    internalCheckboxSelectedRowKeysTemp.splice(rowKeyIndex, 1)
                }
            }
            if (!Array.isArray(selectedRowKeys)) {
                state.internalCheckboxSelectedRowKeys = internalCheckboxSelectedRowKeysTemp
            }
            selectedRowChange({
                row: props.actualRenderTableData.find(x => x[rowKeyFieldName] === rowKey),
                isSelected,
                selectedRowKeys: internalCheckboxSelectedRowKeysTemp,
            })
        }

        function checkboxSelectedAllChange({ isSelected }) {
            const {
                checkboxOption,
                internalCheckboxSelectedRowKeys,
                allRowKeys,
                disableCheckboxSelectedRowKeys,
                disableCheckboxUnselectedRowKeys,
            } = props
            const { selectedAllChange, selectedRowKeys } = checkboxOption
            let internalCheckboxSelectedRowKeysTemp = internalCheckboxSelectedRowKeys.slice(0)
            if (isSelected) {
                let allSelectedKeys = allRowKeys.slice(0)
                if (disableCheckboxUnselectedRowKeys.length > 0) {
                    disableCheckboxUnselectedRowKeys.forEach(rowkey => {
                        let index = allSelectedKeys.indexOf(rowkey)
                        if (index > -1) {
                            allSelectedKeys.splice(index, 1)
                        }
                    })
                }
                internalCheckboxSelectedRowKeysTemp = allSelectedKeys
            } else {
                internalCheckboxSelectedRowKeysTemp = disableCheckboxSelectedRowKeys
            }
            if (!Array.isArray(selectedRowKeys)) {
                state.internalCheckboxSelectedRowKeys = internalCheckboxSelectedRowKeysTemp
            }
            selectedAllChange &&
                selectedAllChange({
                    isSelected,
                    selectedRowKeys: internalCheckboxSelectedRowKeysTemp,
                })
        }

        function radioSelectedRowChange({ rowKey }) {
            const { radioOption, isControlledRadio } = props
            const { selectedRowChange } = radioOption
            if (!isControlledRadio) {
                state.internalRadioSelectedRowKey = rowKey
            }
            selectedRowChange({
                row: props.actualRenderTableData.find(x => x[rowKeyFieldName] === rowKey),
            })
        }

        function getTrKey({ rowData, rowIndex }) {
            let result = rowIndex
            if (props.rowKeyFieldName) {
                result = rowData[props.rowKeyFieldName]
            }
            return result
        }

        function renderingRowKeys(rowKeys) {
            const previewRenderedRowKeys = state.virtualScrollPreviewRenderedRowKeys
            state.virtualScrollRepeatRenderedRowKeys = rowKeys.filter(rowKey => {
                return previewRenderedRowKeys.indexOf(rowKey) !== -1
            })
            state.virtualScrollPreviewRenderedRowKeys = rowKeys
        }

        onMounted(() => {
            emitter.on(EMIT_EVENTS.CHECKBOX_SELECTED_ROW_CHANGE, checkboxSelectedRowChange)
            emitter.on(EMIT_EVENTS.CHECKBOX_SELECTED_ALL_CHANGE, checkboxSelectedAllChange)
            emitter.on(EMIT_EVENTS.RADIO_SELECTED_ROW_CHANGE, radioSelectedRowChange)
            emitter.on(EMIT_EVENTS.BODY_ROW_CLICK, 点击行)

            if (props.checkboxOption) {
                nextTick(() => {
                    sendToCheckboxAll()
                })
            }
        })

        return () => (
            <tbody>
                {/* Measure each column width with additional hidden col */}
                <tr style="height:0;">
                    {props.colgroups.map(column => {
                        const measureTdProps = {
                            key: getDomResizeObserverCompKey(column.key, props.columnsOptionResetTime),
                            tagName: "td",
                            id: column.key,
                            onDomResizeChange: tdSizeChange,
                            style: {
                                padding: 0,
                                border: 0,
                                height: 0,
                            },
                        }
                        return <VueDomResizeObserver {...measureTdProps} />
                    })}
                </tr>
                {/* <span>props.highlightRowKey:{props.highlightRowKey}</span> */}
                {props.actualRenderTableData.map((rowData, rowIndex) => {
                    const trProps = {
                        key: getTrKey({ rowData, rowIndex }),
                        rowIndex,
                        rowData,
                        colgroups: props.colgroups,
                        expandOption: props.expandOption,
                        expandedRowkeys: expandedRowkeys.value,
                        checkboxOption: props.checkboxOption,
                        radioOption: props.radioOption,
                        rowKeyFieldName: props.rowKeyFieldName,
                        allRowKeys: props.allRowKeys,
                        expandRowChange,
                        internalCheckboxSelectedRowKeys: props.internalCheckboxSelectedRowKeys,
                        internalRadioSelectedRowKey: props.internalRadioSelectedRowKey,
                        isVirtualScroll: props.isVirtualScroll,
                        isExpandRow: isExpandRow({
                            rowData,
                            rowIndex,
                        }),
                        cellStyleOption: props.cellStyleOption,
                        cellSpanOption: props.cellSpanOption,
                        highlightRowKey: props.highlightRowKey,
                        eventCustomOption: props.eventCustomOption,
                        cellSelectionData: props.cellSelectionData,
                        editOption: props.editOption,
                        columnCollection: columnCollection,
                        cellSelectionRangeData: props.cellSelectionRangeData,
                        bodyIndicatorRowKeys: props.bodyIndicatorRowKeys,
                    }
                    if (props.showVirtualScrollingPlaceholder) {
                        const trPropsScrolling = {
                            key: getTrKey({ rowData, rowIndex }),
                            colgroups,
                        }
                        if (virtualScrollRepeatRenderedRowKeys.indexOf(rowData[props.rowKeyFieldName]) != -1) {
                            return [<BodyTr {...trProps} />]
                        } else {
                            return <BodyTrScrolling {...trPropsScrolling} />
                        }
                    } else {
                        return [<BodyTr {...trProps} />, getExpandRowComp({ rowData, rowIndex })]
                    }
                })}
            </tbody>
        )
    },
})
